﻿using BCCommon;
using BCMongoEntity.TMS.Location.Branches;
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BCMongoData.TMS.Location.Branches
{
    public class BranchesLocationMongoData : IBranchesLocationMongoData
    {
        private MongoDBCommand<BranchesLocationEntity> mongoCommand;
        private MongoDBCommand<BsonDocument> geoNaerCommand;

        public BranchesLocationMongoData(IMongoDBConfiguration mongoDBConfiguration)
        {
            this.mongoCommand = new MongoDBCommand<BranchesLocationEntity>(mongoDBConfiguration, "BranchesLocation");
            this.geoNaerCommand = new MongoDBCommand<BsonDocument>(mongoDBConfiguration, "BranchesLocation");
        }

        public void Delete(long agentBranchesConfigId)
        {
            this.mongoCommand.DeleteDocumentAsync(d => d.AgentBranchesConfigId == agentBranchesConfigId).GetAwaiter().GetResult();
        }

        public IEnumerable<BranchesLocationNearEntity> GetGeoNearLocationsByCoordinate(double[] location, int maxDistance, List<BsonElement> query, List<BsonElement> projections)
        {
            List<BsonElement> elementList = new List<BsonElement>
            {
                new BsonElement("near", BsonValue.Create(new double[] { Math.Round(location[0], 8), Math.Round(location[1], 8) })),
                new BsonElement("distanceField", "dis"),
                new BsonElement("spherical", true),
                new BsonElement("maxDistance", maxDistance / 6378.137),
                new BsonElement("distanceMultiplier", 6378.137)
            };
            if (query != null)
            {
                elementList.Add(new BsonElement("query", BsonValue.Create(new BsonDocument(query))));
            }

            List<BsonDocument> bsonDocument = new List<BsonDocument>
            {
                new BsonDocument { { "$geoNear", new BsonDocument(elementList) } }
            };
            if (projections != null)
            {
                bsonDocument.Add(new BsonDocument { { "$project", new BsonDocument(projections) } });
            }

            var pipelineDefinition = PipelineDefinition<BsonDocument, BranchesLocationNearEntity>.Create(bsonDocument.ToArray());

            var result = this.geoNaerCommand.Aggregate(pipelineDefinition).GetAwaiter().GetResult();
            return result.ToList();
        }

        public BranchesLocationEntity Insert(BranchesLocationEntity entity)
        {
            this.mongoCommand.InsertDocumentAsync(entity).GetAwaiter().GetResult();
            return this.mongoCommand.SelectDocumentAsync(s => s.AgentBranchesConfigId == entity.AgentBranchesConfigId).GetAwaiter().GetResult();
        }

        public BranchesLocationEntity Update(BranchesLocationEntity entity)
        {
            var builder = Builders<BranchesLocationEntity>.Update
                            .Set(y => y.AgentBranchesConfigId, entity.AgentBranchesConfigId)
                            .Set(y => y.AgentBranchesName, entity.AgentBranchesName)
                            .Set(y => y.Longitude, entity.Longitude)
                            .Set(x => x.Latitude, entity.Latitude)
                            .Set(y => y.Coordinate, new double[] { Math.Round(entity.Longitude, 8), Math.Round(entity.Latitude, 8) })
                            .Set(y => y.IsSend, entity.IsSend)
                            .Set(y => y.IsReceive, entity.IsReceive);
            this.mongoCommand.UpdateDocumentAsync(d => d.AgentBranchesConfigId == entity.AgentBranchesConfigId, builder).GetAwaiter().GetResult();
            return this.mongoCommand.SelectDocumentAsync(s => s.AgentBranchesConfigId == entity.AgentBranchesConfigId).GetAwaiter().GetResult();
        }
    }
}
